package world_2d;

import cell_2d.*;
import java.util.Random; 

public class World {
	public static final int NB_ROWS=4;
	public static final int NB_COLS=8;
	public int generation;
	public boolean b_is_evolving;
	
	public World() {
		// Create the world
		generation = 0;
		b_is_evolving = true;
		Random rand = new Random();
		boolean temp_stat;
		for(int i=0; i<NB_ROWS; i++){
			for(int j=0; j<NB_COLS; j++) {
				temp_stat = rand.nextBoolean();
				world[i][j] = new cell(i, j, temp_stat);
				img_world[i][j] = new cell(i, j, temp_stat);
			}
		}
		// Let each cell know its neighbors
		for(int i=0; i<NB_ROWS; i++){
			for(int j=0; j<NB_COLS; j++) {
				if(i!=(NB_ROWS-1)) {     // North
					world[i][j].add_neighbor(cell.Directions.N.ordinal(), world[i+1][j]);
				}
				if(i!=0) {               // South
					world[i][j].add_neighbor(cell.Directions.S.ordinal(), world[i-1][j]);
				}
				if(j != (NB_COLS-1)) {   // East
					world[i][j].add_neighbor(cell.Directions.E.ordinal(), world[i][j+1]);
					if(i!=0) {           // South-East
						world[i][j].add_neighbor(cell.Directions.SE.ordinal(), world[i-1][j+1]);
					}
					if(i!=(NB_ROWS-1)) { // North-East
						world[i][j].add_neighbor(cell.Directions.NE.ordinal(), world[i+1][j+1]);
					}
				}
				if(j != 0) {             // West
					world[i][j].add_neighbor(cell.Directions.W.ordinal(), world[i][j-1]);
					if(i!=0) {           // South-West
						world[i][j].add_neighbor(cell.Directions.SW.ordinal(), world[i-1][j-1]);
					}
					if(i!=(NB_ROWS-1)) { // North-East
						world[i][j].add_neighbor(cell.Directions.NW.ordinal(), world[i+1][j-1]);
					}
				}
			}
		}
	}
	
	public void go_to_next_generation() {
		int nb_random_birth = 0;
		// For each cell of the world, update the status of its copy in img_world
		for(int i=0; i<NB_ROWS; i++) {
			for(int j=0; j<NB_COLS; j++) {
				if(world[i][j].get_age() == 6) { // new rule
					img_world[i][j].set_status(false); // die because too old
					img_world[i][j].reset_age();
					nb_random_birth++;	// A new birth for each death by age
				} else {
					int nb_neighbors = world[i][j].get_num_live_neighbors();
					if(world[i][j].get_status() == true) {
						if((nb_neighbors < 2) || (nb_neighbors > 3)) { // under-population or overcrowding
							img_world[i][j].set_status(false);
							img_world[i][j].reset_age();
						} else {
							// Live on to the next generation
							img_world[i][j].increment_age();
						}
					} else {
						if(nb_neighbors == 3) {
							img_world[i][j].set_status(true);
						}
					}
				}
			}
		}
		
		// Select nb_random_birth cells: if they are dead, make them alive else do nothing.
		int temp_row_idx;
		int temp_col_idx;
		Random rand = new Random();
		while(nb_random_birth != 0) {
			temp_row_idx = rand.nextInt(NB_ROWS);
			temp_col_idx = rand.nextInt(NB_COLS);
			if(img_world[temp_row_idx][temp_col_idx].get_status() == false) {
				img_world[temp_row_idx][temp_col_idx].set_status(true);
			}
			nb_random_birth--;
		}
		
		// Update the status of each cell in the world from the status of its copy in img_world.
		// Also check if the world is still evolving.
		boolean b_is_the_world_empty = true;
		for(int i=0; i<NB_ROWS; i++) {
			for(int j=0; j<NB_COLS; j++) {
				world[i][j].set_status(img_world[i][j].get_status());
				world[i][j].set_age(img_world[i][j].get_age());
				if(b_is_the_world_empty == true) {
					if(world[i][j].get_status() == true) {
						b_is_the_world_empty = false;
					}
				}
			}
		}
		if(b_is_the_world_empty == true) {
			b_is_evolving = false;
		}

		// Update the generation
		generation++;
	}
	
	public void display() {
		System.out.println("================");
		System.out.printf("Generation %d%n", generation);
		System.out.println("================");
		for(int i=0; i<NB_ROWS; i++) {
			for(int j=0; j<NB_COLS; j++) {
				if(world[i][j].get_status() == true) {
					System.out.print("X ");
				} else {
					System.out.print("O ");
				}
			}
			System.out.println(); // Newline
		}	
	}
	
	private cell [][] world = new cell[NB_ROWS][NB_COLS]; // Note: cell objects are not created here.
	private cell [][] img_world = new cell[NB_ROWS][NB_COLS]; // Note: cell objects are not created here.
}
